import os
import sys
import subprocess
import shutil
import re
import getpass
import glob
import hashlib
import fnmatch

ERR_MESSAGES = []

# 定义颜色代码
class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

def print_colored(message, color):
    print(f"{getattr(bcolors, color)}{message}{bcolors.ENDC}")

def message_success(message):
    print_colored(message, 'OKGREEN')

def message_fail(message):
    print_colored(message, 'FAIL')

def appemd_mention_message(message):
    ERR_MESSAGES.extend(message)

def clear_mention_message():
    ERR_MESSAGES.clear()

def print_mention_message():
    for msg in ERR_MESSAGES:
        print_colored(msg, 'OKBLUE')

def print_trace_message(module, message):
    print_colored(f'{module}: {message}', 'OKBLUE')

def exec_command(make_command, op, cwd=None, exit = True, env=None):
    try:
        subprocess.check_call(make_command, cwd = cwd, env=env)
        message_success(f'{op} successful.')
        return True
    except subprocess.CalledProcessError as e:
        message_fail(f'{op} failed: {e}, {exit}')
        if exit:
            print_mention_message()
            sys.exit(1)
        return False

def exec_doing(command, op, exit = True):
    try:
        command
        message_success(f'{op} successful.')
        return True
    except subprocess.SubprocessError as e:
        message_fail(f'{op} failed: {e}')
        if exit:
            print_mention_message()
            sys.exit(1)
        return False

def copy_files_ignoring_hidden(src, dst):
    os.makedirs(dst, exist_ok=True)
    if os.path.isdir(src):
        for item in os.listdir(src):
            # 忽略以点开头的文件和目录（隐藏文件/目录）
            if not item.startswith('.'):
                s = os.path.join(src, item)
                d = os.path.join(dst, item)
                # os.makedirs(d, exist_ok=True)
                if os.path.isdir(s):
                    if not os.path.exists(d):
                        os.makedirs(d)
                    copy_files_ignoring_hidden(s, d)
                elif os.path.isfile(s):
                    shutil.copy2(s, d)
    elif os.path.isfile(src):
        # 源不是以点开头的隐藏文件，所以复制它
        shutil.copy2(src, dst)

def replace_value_in_file(file_path, key, new_value):
    """
    :param file_path: 要修改的文件路径
    """
    # 编译正则表达式，用于匹配key=value
    pattern = re.compile(rf'^{key}=.*$', re.MULTILINE)

    # 读取文件内容
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()

    # 使用正则表达式替换内容
    # 注意：这里假设key只出现一次，并且整行只有key=value。如果有多行或key前后有其他内容，请调整正则表达式。
    new_content = pattern.sub(f'{key}={new_value}', content)

    # 写回文件
    with open(file_path, 'w', encoding='utf-8') as file:
        file.write(new_content)

def patten_files_exist(pattern):
    matches = glob.glob(pattern)
    # 遍历匹配项
    for match in matches:
        if not os.path.exists(match):
            return False
    return True

def move_matching_files(pattern, destination, reserve = False):
    """
    Move all files and directories matching the given pattern to the destination directory.

    :param pattern: The glob pattern to match files and directories.
    :param destination: The destination directory to move the matched items to.
    """
    # 确保目标目录存在，如果不存在则创建它
    if not os.path.exists(destination):
        os.makedirs(destination)

    # 使用glob模块查找所有匹配的文件和目录
    matches = glob.glob(pattern)

    # 遍历匹配项
    for match in matches:
        # 构建目标路径
        # 注意：这里假设我们想要保留原始的文件/目录名作为目标路径的一部分
        destination_path = os.path.join(destination, os.path.basename(match))

        # 调用shutil.move()来移动每个匹配项
        try:
            if not reserve:
                shutil.move(match, destination_path)
            else:
                if os.path.isfile(match):
                    shutil.copy2(match, destination_path)
                elif os.path.isdir(match):
                    shutil.copytree(match, destination_path, dirs_exist_ok=True)
            print_colored(f"Moved {match} to {destination_path}", "OKBLUE")
        except Exception as e:
            # 处理移动过程中可能发生的异常
            print_colored(f"Failed to move {match}. Reason: {e}", "WARNING")

def copy_files_with_pattern(src_dir, dst_dir, pattern="*"):
    """
    将源目录及其子目录中匹配指定后缀的文件拷贝到目标目录，保持子目录结构
    :param src_dir: 源目录路径（如 "/home/wlxuz/libz"）
    :param dst_dir: 目标目录路径（如 "/mnt/libz"）
    :param pattern: 匹配模式（如 "*.h"）
    """
    # 遍历源目录及其子目录
    for root, dirs, files in os.walk(src_dir):
        relative_path = os.path.relpath(root, src_dir)
        target_dir = os.path.join(dst_dir, relative_path)

        for file in files:
            if fnmatch.fnmatch(file, pattern):
                os.makedirs(target_dir, exist_ok=True)
                src_file = os.path.join(root, file)
                dst_file = os.path.join(target_dir, file)
                shutil.copy2(src_file, dst_file)
                with open(src_file, 'rb') as src_f, open(dst_file, 'wb') as dst_f:
                    shutil.copyfileobj(src_f, dst_f, length=1024 * 1024)  # 1MB 分块
                print(f"Copied: {src_file} -> {dst_file}")

def hash_file(filepath):
    """计算单个文件的SHA-256哈希值"""
    sha256_hash = hashlib.sha256()
    with open(filepath, "rb") as f:
        # 读取文件内容并更新哈希对象
        for byte_block in iter(lambda: f.read(4096), b""):
            sha256_hash.update(byte_block)
    return sha256_hash.hexdigest()

def hash_str(str:dict):
    sha256_hash = hashlib.sha256()
    for d in str:
        sha256_hash.update(d.__str__().encode('utf-8'))
    return sha256_hash.hexdigest()

def hash_dir(directory, extra:dict = None):
    """递归计算目录及其所有子目录和文件的SHA-256哈希值"""
    hashes = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            filepath = os.path.join(root, file)
            file_hash = hash_file(filepath)
            hashes.append(file_hash)
    if extra is not None:
        hashes.append(hash_str(extra))

    # 将所有文件的哈希值连接起来，并计算整个字符串的哈希值
    concatenated_hash = ''.join(sorted(hashes))  # 排序以确保一致性
    dir_hash = hashlib.sha256(concatenated_hash.encode('utf-8')).hexdigest()
    return dir_hash

def hash_compare(src_dir, record_dir, extra= None):
    if not os.path.exists(f'{record_dir}/.hash'):
        return False
    src_hash = hash_dir(src_dir, extra)
    dst_hash = ''
    with open(f'{record_dir}/.hash', 'r') as file:
        dst_hash = file.read()
    return src_hash == dst_hash

def hash_write(src_dir, record_dir, succ:bool, extra:dict = None):
    if not succ:
        if os.path.exists(f'{record_dir}/.hash'):
            os.remove(f'{record_dir}/.hash')
        return

    src_hash = hash_dir(src_dir, extra)
    dst_hash = ''
    with open(f'{record_dir}/.hash', 'w') as file:
        file.write(src_hash)
    return src_hash == dst_hash

def exist_substr_module(module, str):
    for m in module:
        if str in m:
            return True
    return False


def common_prefix(files):
    if not files:
        return ""
    # Initialize the common prefix with the first string
    common = files[0]

    # Iterate over the remaining strings
    for file in files[1:]:
        i = 0
        while i < len(common) and i < len(file) and common[i] == file[i]:
            i += 1
        common = common[:i]
        if not common:
            break

    return common

def find_subdirs_with_suffix(directory_path, suffix):
    matching_dirs = []

    # Walk through the directory tree
    for root, dirs, files in os.walk(directory_path):
        suffix_files = []
        for file in files:
            # Check if the directory name ends with the specified suffix
            if fnmatch.fnmatch(file, f'*{suffix}'):
                suffix_files.append(file)
        if len(suffix_files) > 0:
            prefix = common_prefix(suffix_files)
            matching_dirs.append((prefix,root))

    # If we found matching directories, return them as a list
    # If you only want to return the first match or a specific behavior, modify accordingly
    if matching_dirs:
        return matching_dirs  # You can return the first one if needed: return matching_dirs[0]
    else:
        return None

def remove_config_suffix(s):
    """
    如果字符串末尾是'Config'或'-config'，则去掉，否则不变。

    参数:
    s (str): 输入的字符串。

    返回:
    str: 处理后的字符串。
    """
    # 定义要移除的后缀
    suffixes_to_remove = ['Config', '-config', '-']

    # 遍历后缀并检查字符串是否以这些后缀结尾
    for suffix in suffixes_to_remove:
        if s.endswith(suffix):
            # 如果字符串以该后缀结尾，则移除它并返回结果
            return s[:-len(suffix)]

    # 如果字符串不以任何指定的后缀结尾，则返回原始字符串
    return s

def capital_literal(str):
    return f'{str[0].upper()}{str[1:]}'